﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using MobilePulginBase;
using System.Xml;
using System.IO;
using System.Reflection;
using System.Windows.Forms;


namespace MobilePlugin.Core
{
    public class PluginManager
    {
        private static PluginManager _self = null;
        private static Dictionary<string, IPlugin> _cache = null;
        private static string currentDir = "";
        private static string pluginDir = "";
        private const string XML_ROOT_ELEM = "plugins";
        private const string XML_PLG_ELEM = "plugin";
        private const string XML_ATTR_NAME = "name";
        private const string XML_ATTR_REQ = "required";
        private const string XML_ATTR_VER = "version";
        private const string XML_ATTR_ASM = "assembly";
        private const string XML_ATTR_CLS = "class";
        private const string XML_ATTR_PARENT = "parent";
        private const string XML_ATTR_INDEX = "index";

        private const int ERR_FATAL = -999;
        private const int ERR_GENERAL = -1;


        private PluginManager()
        {
            _cache = new Dictionary<string, IPlugin>();
            currentDir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
            if (currentDir.Substring(currentDir.Length - 2, 1) != "\\")
            {
                currentDir = currentDir + "\\";
            }
            pluginDir = currentDir + "Plugins\\";
        }
        /// <summary>
        /// 获取插件列表
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, IPlugin> GetPlugins()
        {
            return _cache;
        }
        /// <summary>
        /// 获取一个插件的实例
        /// </summary>
        /// <param name="pluginName">插件名称</param>
        /// <returns></returns>
        public IPlugin FindPlugin(string pluginName)
        {
            return _cache[pluginName];
        }

        public static PluginManager GetInstance
        {
            get
            {
                if (_self == null)
                    _self = new PluginManager();
                return _self;
            }
        }
        /// <summary>
        /// 错误转换方法
        /// </summary>
        /// <param name="ex">被抛出的异常</param>
        /// <param name="requried">模块是否必须</param>
        /// <returns>需要输出给用户的信息</returns>
        private string ParseException(Exception ex, bool requried)
        {
            string str = "";
            if (ex is FileNotFoundException)
            {
                if (requried)
                {
                    str = "系统核心模块丢失，应用将强制退出，请联系管理员";
                }
                else
                {
                    str = "系统有模块丢失，您可能无法使用系统的某些功能，您是否继续登录系统";
                }
            }
            else if (ex is MissingMethodException)
            {
                if (requried)
                    str = "系统核心模块无法被正常加载，应用将强制退出";
                else
                    str = "系统有模块不能被正常加载，您可能无法使用系统的某些功能，您是否继续登录系统";
            }
            else
            {
                if (requried)
                    str = "核心模块加载异常,原因：" + ex.Message + ",应用将强制退出";
                else
                    str = "系统有模块加载时出现异常,原因：" + ex.Message + ",您可能无法使用系统的某些功能，您是否继续登录系统";
            }
            return str;
        }

        /// <summary>
        /// 分析插件定义文件
        /// </summary>
        /// <param name="pluginDefFile">插件定义文件路径</param>
        /// <returns></returns>
        private List<IPlugin> AnalysisPlugin(string pluginDefFile, out int errCode)
        {
            List<IPlugin> pluginList;
            errCode = 0;

            using (StreamReader sdr = new StreamReader(pluginDefFile))
            {
                using (XmlTextReader xdr = new XmlTextReader(sdr))
                {
                    pluginList = new List<IPlugin>();
                    while (xdr.Read())
                    {
                        if (xdr.NodeType == XmlNodeType.Element)
                        {
                            if (xdr.Name == XML_ROOT_ELEM)
                                continue;
                            if (xdr.Name == XML_PLG_ELEM)
                            {
                                string pluginFile = pluginDir + xdr[XML_ATTR_ASM];
                                string pluginCls = xdr[XML_ATTR_CLS];
                                int pluginIdx = int.Parse(xdr[XML_ATTR_INDEX]);

                                IPlugin plugin = null;
                                try
                                {
                                    plugin = (IPlugin)Assembly.LoadFrom(pluginFile).CreateInstance(pluginCls);
                                    int remoteVer = int.Parse(xdr[XML_ATTR_VER]);
                                    if (plugin.Version < remoteVer && int.Parse(xdr[XML_ATTR_REQ]) == 1)
                                    {
                                        MessageBox.Show("你有核心插件不是最新版本请升级,请先将插件升级到最新版本");
                                        errCode = -2;
                                        for (int ii = 0; ii < pluginList.Count; ii++)
                                        {
                                            pluginList[ii].Dispose();
                                        }
                                        pluginList.Clear();
                                        return null;
                                    }
                                    plugin.Index = pluginIdx;
                                    pluginList.Add(plugin);
                                }
                                catch (Exception ex)
                                {
                                    string retStr = null;
                                    if (int.Parse(xdr[XML_ATTR_REQ]) == 1)
                                    {
                                        errCode = ERR_FATAL;
                                        retStr = ParseException(ex, true);
                                        MessageBox.Show(retStr, "严重错误", MessageBoxButtons.OK,
                                            MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
                                        for (int ii = 0; ii < pluginList.Count; ii++)
                                        {
                                            pluginList[ii].Dispose();
                                        }
                                        pluginList.Clear();
                                        return null;

                                    }
                                    else
                                    {
                                        errCode = ERR_GENERAL;
                                        retStr = ParseException(ex, false);
                                        DialogResult dr = MessageBox.Show(retStr, "插件加载错误", MessageBoxButtons.YesNo,
                                            MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
                                        if (dr == DialogResult.No)
                                        {
                                            for (int ii = 0; ii < pluginList.Count; ii++)
                                            {
                                                pluginList[ii].Dispose();
                                            }
                                            pluginList.Clear();
                                            return null;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return pluginList;
        }
        /// <summary>
        /// 通过插件定义文件加载插件
        /// </summary>
        /// <param name="pluginDefFile"></param>
        public void LoadPlugins(string pluginDefFile)
        {
            int errCode = 0;
            List<IPlugin> list = AnalysisPlugin(pluginDefFile, out errCode);
            if (errCode == ERR_FATAL)
                return;
            if (errCode == ERR_GENERAL && list == null)
                return;

            for (int i = 0; i < list.Count; i++)
            {
                IPlugin p = list[i];
                _cache.Add(p.Name, p);
            }
            list = null;
        }

        /// <summary>
        /// 卸载插件
        /// </summary>
        public void UnLoadPlugins()
        {
            foreach (KeyValuePair<string, IPlugin> pair in _cache)
            {
                pair.Value.Dispose();
            }
            _cache.Clear();
            _cache = null;
        }

    }
}
